refactor(integration): extract MCPIntegrator.install#1245
Conversation
…r_install Strangler-fig stage 1: move install orchestration into run_mcp_install() while keeping MCPIntegrator.install as the public entrypoint.
|
@microsoft-github-policy-service agree |
APM Review Panel:
|
| Persona | B | R | N | Takeaway |
|---|---|---|---|---|
| Python Architect | 0 | 1 | 2 | Strangler-fig shell is clean; install function back-references 9 private MCPIntegrator statics, capping test isolation and leaving the extraction half-done. |
| CLI Logging Expert | 0 | 3 | 2 | 2 silent-failure gaps in non-Rich path (errors swallowed), STATUS_SYMBOLS bracket convention broken in Rich path, 1 missing progress fallback. No Unicode chars found. |
| DevX UX Expert | 0 | 0 | 1 | Clean extraction -- public API, all 12 args, error paths, and scope filtering fully preserved. One pre-existing Gemini cwd inconsistency noted for follow-up. |
| Supply Chain Security Expert | 0 | 0 | 1 | Pure refactor preserves all security controls; one nit on lazy back-import ordering contract that could silently break if module load order changes. |
| OSS Growth Hacker | 0 | 0 | 2 | Pure internal refactor; positive contributor-experience delta. No conversion surface touched. Two nits around discoverability signaling. |
| Doc Writer | 0 | 1 | 1 | Two docs carry hardcoded mcp_integrator.py line numbers that may have drifted after the extraction; no CHANGELOG entry needed for this internal refactor; new module docstrings are adequate. |
| Test Coverage Expert | 0 | 1 | 0 | Unit tests flow through run_mcp_install; all integration tests mock the thin delegate, leaving the ~500-line extracted body invisible at the integration tier -- one integration-with-fixtures test would close the gap. |
B = blocking-severity findings, R = recommended, N = nits.
Counts are signal strength, not gates. The maintainer ships.
Top 5 follow-ups
- [CLI Logging Expert] Per-server install failure messages are silently swallowed in non-Rich environments (lines 457-458, 550-551 -- no
elsebranch afterelif console:error blocks). -- Silent failures in headless/CI environments are the highest-impact user-facing defect in this diff. Anelse: logger.error(f"{dep} -- failed for all runtimes")branch closes the gap with one line each. - [Test Coverage Expert] All integration tests patch
MCPIntegrator.installat the delegate boundary, leaving run_mcp_install's ~500-line body invisible at the integration tier (outcome: missing). -- Silent drift in argument order, early-return logic, or exception propagation inside run_mcp_install would reach users before any test catches it. One un-mocked integration-with-fixtures test intests/integration/test_mcp_integrator_install.pycloses the gap. - [CLI Logging Expert] Rich path emits bare
>+xsymbols; STATUS_SYMBOLS convention requires bracket-enclosed[>][+][x]. Same event renders differently depending on Rich availability. -- Fix is mechanical: emit[cyan]\[>][/cyan]or route through STATUS_SYMBOLS dict. - [Python Architect]
run_mcp_installback-references 9 private MCPIntegrator static methods, capping test isolation and leaving the strangler-fig half-done. -- Expected intermediate state; tracking it as a follow-up extraction issue is the only way the isolation gain gets realized. - [Doc Writer] Two docs cite hardcoded
mcp_integrator.pyline numbers (security-and-supply-chain.md:88,mcp-as-primitive.md:132) that may have drifted after the extraction. -- Replace with file-path-only citations or commit-SHA permalinks to prevent rot on the next refactor.
Architecture
classDiagram
direction LR
class MCPIntegrator {
+install(mcp_deps, ...) int
-_detect_runtimes(scripts) list
-_gate_project_scoped_runtimes(...) list
-_install_for_runtime(...) bool
-_detect_mcp_config_drift(...) set
-_append_drifted_to_install_list(...) None
-_apply_overlay(...) None
-_build_self_defined_info(dep) dict
-_check_self_defined_servers_needing_installation(...) list
}
class run_mcp_install {
<<ModuleFunction>>
+run_mcp_install(mcp_deps, ...) int
}
class MCPServerOperations {
+validate_servers_exist(names) tuple
+check_servers_needing_installation(...) list
+batch_fetch_server_info(servers) dict
}
class InstallScope {
<<Enum>>
USER
PROJECT
}
MCPIntegrator ..> run_mcp_install : delegates install() to
run_mcp_install ..> MCPIntegrator : calls 9 private statics
run_mcp_install ..> MCPServerOperations : registry ops
run_mcp_install ..> InstallScope : scope filtering
class run_mcp_install:::touched
class MCPIntegrator:::touched
classDef touched fill:#fff3b0,stroke:#d47600
flowchart TD
A(["CLI: apm install / apm mcp install"]) --> B["MCPIntegrator.install()\nmcp_integrator.py"]
B --> C["run_mcp_install()\nmcp_integrator_install.py"]
C --> D{"runtime param?"}
D -- yes --> E["target_runtimes = [runtime]"]
D -- no --> F["load apm.yml + RuntimeManager\ndetect installed runtimes"]
F --> G["MCPIntegrator._detect_runtimes(scripts)\nintersect installed with script runtimes"]
G --> E
E --> H["MCPIntegrator._gate_project_scoped_runtimes()"]
H --> I{"registry_deps?"}
I -- yes --> J["MCPServerOperations.validate_servers_exist()"]
J --> K["MCPIntegrator._detect_mcp_config_drift()"]
K --> L["MCPServerOperations.batch_fetch_server_info()"]
L --> M["MCPIntegrator._install_for_runtime() per server per runtime"]
I -- no --> N{"self_defined_deps?"}
M --> N
N -- yes --> O["MCPIntegrator._check_self_defined_servers_needing_installation()"]
O --> P["MCPIntegrator._install_for_runtime()"]
P --> Q["return configured_count"]
N -- no --> Q
sequenceDiagram
participant CLI
participant MCPIntegrator
participant run_mcp_install
participant MCPServerOperations
CLI->>MCPIntegrator: install(mcp_deps, ...)
MCPIntegrator->>run_mcp_install: lazy import + delegate (all args forwarded)
run_mcp_install->>MCPIntegrator: lazy import back (_detect_runtimes, _gate_project_scoped_runtimes, 7 more statics)
run_mcp_install->>MCPServerOperations: validate_servers_exist(names)
MCPServerOperations-->>run_mcp_install: valid_servers, invalid_servers
run_mcp_install->>MCPIntegrator: _detect_mcp_config_drift(deps, stored)
MCPIntegrator-->>run_mcp_install: drifted set
run_mcp_install->>MCPServerOperations: batch_fetch_server_info(servers)
MCPServerOperations-->>run_mcp_install: server_info_cache
loop per server per runtime
run_mcp_install->>MCPIntegrator: _install_for_runtime(rt, dep, ...)
MCPIntegrator-->>run_mcp_install: bool
end
run_mcp_install-->>CLI: configured_count
Recommendation
Merge as-is. The extraction is architecturally correct, the public API is fully preserved, and no security or behavioral regression was found by any panelist. Open three follow-up issues immediately post-merge: (1) close the silent-failure logging gaps in non-Rich paths (cli-logging-expert, highest blast radius), (2) add one un-mocked integration-with-fixtures test for run_mcp_install (test-coverage-expert, closes the integration-tier coverage gap), and (3) track the 9 private back-references as the next strangler-fig extraction step (python-architect). The doc line-number rot fix is a fast PR that can land in parallel.
Full per-persona findings
Python Architect
- [recommended]
run_mcp_installcalls 9 private MCPIntegrator static methods back into the host module atsrc/apm_cli/integration/mcp_integrator_install.py
The strangler-fig achieves file-size reduction but not isolation: unit tests for run_mcp_install must still patch MCPIntegrator private methods. A cleaner end-state moves those helpers into mcp_integrator_install.py (or a shared module) so the extracted module is self-contained. This is a follow-up, not a blocker. - [nit]
_get_consoleimported via mcp_integrator re-export instead of directapm_cli.utils.consoleimport atsrc/apm_cli/integration/mcp_integrator_install.py:62
A direct import from apm_cli.utils.console removes the re-export indirection and the noqa annotation, making the dependency graph cleaner. - [nit] Lazy import of entire MCPIntegrator module just to access module-level
_is_vscode_availableatsrc/apm_cli/integration/mcp_integrator_install.py:60
_is_vscode_availableis a module-level function, not a class method. It could be moved to utils/ or imported directly without pulling the MCPIntegrator class itself.
CLI Logging Expert
- [recommended] Per-server failure messages have no logger fallback -- silent in non-Rich environments at
src/apm_cli/integration/mcp_integrator_install.py
Lines 457-458 and 550-551 useelif console: console.print(...)error with noelsebranch. When Rich is unavailable, a per-server installation failure produces zero output.
Suggested: Addelse: logger.error(f"{dep} -- failed for all runtimes")after eachelif console:error block. - [recommended] Rich console path renders bare
>,+,x-- deviates from STATUS_SYMBOLS bracket convention atsrc/apm_cli/integration/mcp_integrator_install.py
STATUS_SYMBOLS convention defines[>],[+],[x]as full bracket-enclosed ASCII symbols. Rich path emits[cyan]>[/cyan](renders as bare>) while fallback logger path correctly uses bracket notation.
Suggested: Emit[cyan]\[>][/cyan]to preserve bracket notation, or use STATUS_SYMBOLS dict consistently. - [recommended] Per-server progress has no logger fallback -- silent in non-Rich environments at
src/apm_cli/integration/mcp_integrator_install.py
if console:blocks for per-server progress (lines 422, 428, 513, 522) have noelsebranches. Non-Rich users see no per-server progress during install loop.
Suggested: Addelse: logger.progress(f"{dep}: {action_text.lower()} for {', '.join(target_runtimes)}")after each console-only progress block. - [nit] Closing footer
+-prefix is tree-drawing syntax, not STATUS_SYMBOLS atsrc/apm_cli/integration/mcp_integrator_install.py
Consider[*] Configured N serversusing STATUS_SYMBOLS success symbol for the closing line, reserving+-for structural tree nodes only. - [nit] Verbose runtime-detection block is console-only with incomplete logger parallel at
src/apm_cli/integration/mcp_integrator_install.py
Console block emits 4 lines; logger else block emits 2-3. Agent consumers miss the Runtime Detection label and Target line in verbose mode.
DevX UX Expert
- [nit] Gemini runtime detection uses
Path.cwd()instead ofproject_root_pathatsrc/apm_cli/integration/mcp_integrator_install.py:174
Pre-existing in mcp_integrator.py, faithfully copied here. A future caller passing an explicitproject_rootwill silently get wrong gemini detection. Worth a follow-up fix but not introduced by this PR.
Supply Chain Security Expert
- [nit] Lazy circular import pulls private symbols from the delegating module at
src/apm_cli/integration/mcp_integrator_install.py:60
run_mcp_install()lazily imports MCPIntegrator,_get_console, and_is_vscode_availableback from mcp_integrator. Creates an implicit ordering contract invisible to future refactors. Consider importing_get_consoledirectly fromapm_cli.utils.consoleand moving_is_vscode_availableto a shared utils module.
OSS Growth Hacker
- [nit] New module is a contributor-experience win -- worth a one-liner in CHANGELOG at
CHANGELOG.md
Extracting a 500-line method lowers activation energy for first-time contributors who want to extend the install pipeline. - [nit] Module name
mcp_integrator_install.pyis navigable but not self-documenting atsrc/apm_cli/integration/mcp_integrator_install.py:1
A one-line module docstring -- e.g.# Install pipeline for MCP packages. Entry point: run_mcp_install()-- would make the file self-describing on first open.
Auth Expert -- inactive
PR is a pure strangler-fig refactor of MCP install orchestration; no auth, token management, credential resolution, AuthResolver, or HTTP authorization surfaces are touched.
Doc Writer
- [recommended] Hardcoded source line numbers in docs may have drifted after the strangler-fig extraction at
docs/src/content/docs/enterprise/security-and-supply-chain.md:88
docs/enterprise/security-and-supply-chain.md citesmcp_integrator.py:205,219-221and docs/producer/author-primitives/mcp-as-primitive.md citesmcp_integrator.py:124-145. Hardcoded line numbers in docs rot on every refactor.
Suggested: Remove line-number suffixes and cite only the file path, or replace with a GitHub permalink to a specific commit SHA. Apply the same fix indocs/src/content/docs/producer/author-primitives/mcp-as-primitive.md:132. - [nit]
docs/enterprise/security.mdprose referencesMCPIntegrator.installas a method call -- accurate but omits new module location atdocs/src/content/docs/enterprise/security.md
Public API is preserved so no correctness regression. If the source path is ever updated in this page, note that the install logic now lives inmcp_integrator_install.py.
Test Coverage Expert
- [recommended] Integration tests mock the thin delegate, leaving
run_mcp_installinvisible to integration-tier coverage
All integration tests (test_policy_install_e2e.py, test_selective_install_mcp.py, test_install_local_bundle_e2e.py, test_global_mcp_lockfile_e2e.py) patchMCPIntegrator.installat the method boundary. After the strangler-fig extraction, this patch short-circuits the thin delegate before it can callrun_mcp_install(). Unit tests in test_transitive_mcp.py DO flow through run_mcp_install (they only mock_install_for_runtime), so there is unit-tier signal. But the install pipeline surface floor is integration-with-fixtures -- and that tier is now a gap.
Suggested: Add one integration-with-fixtures test intests/integration/test_mcp_integrator_install.pythat does NOT mockMCPIntegrator.installorrun_mcp_installand exercises a real install invocation through the thin delegate.
Proof (missing at integration-with-fixtures):tests/integration/test_mcp_integrator_install.py::test_run_mcp_install_delegates_full_orchestration-- proves: The full install orchestration body in run_mcp_install is reachable and produces correct output via the thin delegate [devx, portability-by-manifest, secure-by-default]
This panel is advisory. It does not block merge. Re-apply the
panel-review label after addressing feedback to re-run.
Note
🔒 Integrity filter blocked 2 items
The following items were blocked because they don't meet the GitHub integrity level.
- refactor(integration): extract MCPIntegrator.install #1245
pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved". - #1245
pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
To allow these resources, lower min-integrity in your GitHub frontmatter:
tools:
github:
min-integrity: approved # merged | approved | unapproved | noneGenerated by PR Review Panel for issue #1245 · ● 3.3M · ◷
|
@danielmeppiel sorry for the extra pings earlier... i realized today that repeated review reminders can be counterproductive, lesson learned and i will avoid doing that going forward... |
danielmeppiel
left a comment
There was a problem hiding this comment.
Please address all comments flagged "recommended" per persona in the panel review. Thank you!
…ct-mcp-integrator-install
…ct-mcp-integrator-install
Fixes #1004
Description
This PR applies strangler-fig stage 1 for MCP install orchestration: the implementation of
MCPIntegrator.installis moved intorun_mcp_install()insrc/apm_cli/integration/mcp_integrator_install.py.MCPIntegrator.installremains a thin delegate so the public API and existing call sites stay the same.Motivation:
mcp_integrator.pyis dominated by a very largeinstallmethod; extracting it improves readability and makes later refactors safer without changing behavior.Compatibility: Imports inside
run_mcp_install()keep test patch targets working (e.g.apm_cli.integration.mcp_integrator._get_console,MCPIntegrator._install_for_runtime)._get_consolestays imported onmcp_integratorwithnoqaso patches that target that module attribute keep working.Type of change
Testing
After
uv sync --extra dev:Result: 265 passed.